package com.evil.activiti.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.evil.activiti.api.RemoteActivityService;
import com.evil.activiti.cmd.GetDbSqlSessionCmd;
import com.evil.activiti.enums.EventTypeEnum;
import com.evil.activiti.listener.TaskRefuseListener;
import com.evil.activiti.service.ActivityService;
import com.evil.activiti.service.FlowConditionService;
import com.evil.activiti.util.ActivityUtil;
import com.evil.activiti.util.BpmnModelUtil;
import com.evil.application.api.RemoteApplicationOrderNodeService;
import com.evil.application.api.RemoteApplicationOrderService;
import com.evil.application.enums.process.CompleteTypeEnum;
import com.evil.common.account.dto.user.UserEnterpriseDTO;
import com.evil.common.activiti.enums.HandleTypeEnum;
import com.evil.common.activiti.enums.SequenceFlowTypeEnum;
import com.evil.common.application.dto.order.node.ChangeOrderNodeDataReqDTO;
import com.evil.common.application.dto.process.*;
import com.evil.common.application.dto.process.node.NodeBaseDTO;
import com.evil.common.core.entity.QueryModel;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import com.github.pagehelper.PageInfo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.process.model.payloads.GetProcessInstancesPayload;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.runtime.TaskRuntime;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.db.DbSqlSession;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 流程服务
 *
 * @author 15587
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class ActivityServiceImpl implements ActivityService, RemoteActivityService {

    private final RemoteApplicationOrderService remoteApplicationOrderService;

    private final RemoteApplicationOrderNodeService remoteApplicationOrderNodeService;

    private final FlowConditionService flowConditionService;

    private final RepositoryService repositoryService;

    private final RuntimeService runtimeService;

    private final HistoryService historyService;

    private final TaskService taskService;

    private final TaskRuntime taskRuntime;

    private final ProcessRuntime processRuntime;

    private final ManagementService managementService;

    /**
     * 部署流程
     *
     * @param processDeploymentReqDTO processDeploymentReqDTO
     * @return ProcessDeploymentRespDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public ProcessDeploymentRespDTO processDeployment(ProcessDeploymentReqDTO processDeploymentReqDTO) {
        log.info("【部署流程】，参数：{}", JSON.toJSONString(processDeploymentReqDTO));

        Long processId = processDeploymentReqDTO.getProcessId();
        String deploymentName = processDeploymentReqDTO.getDeploymentName();

        String resourceName = ActivityUtil.getResourceName(processId);
        BpmnModel bpmnModel = new BpmnModelUtil().createBpmnModel(processDeploymentReqDTO);

        // 部署流程
        Deployment deployment = repositoryService.createDeployment()
                .name(deploymentName)
                .addBpmnModel(resourceName, bpmnModel)
                .deploy();

        ProcessDeploymentRespDTO processDeploymentRespDTO = new ProcessDeploymentRespDTO();
        processDeploymentRespDTO.setProcessKey(deployment.getId());
        return processDeploymentRespDTO;
    }

    /**
     * 获取流程部署列表
     *
     * @param queryModel queryModel
     * @return List
     */
    @Override
    public PageInfo<ProcessDefinitionRespDTO> getDefinitions(QueryModel<Long> queryModel) {
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        if (queryModel.getCheckParam().isPresent()) {
            processDefinitionQuery.processDefinitionKey(ActivityUtil.getProcessId(queryModel.getParam()));
        }

        List<ProcessDefinitionRespDTO> processDefinitions = processDefinitionQuery.listPage(
                queryModel.getStartIndex(), queryModel.getEndIndex()).stream()
                .map(e -> {
                    ProcessDefinitionRespDTO processDefinitionRespDTO = new ProcessDefinitionRespDTO();
                    processDefinitionRespDTO.setProcessDefinitionId(e.getId());
                    processDefinitionRespDTO.setName(e.getName());
                    processDefinitionRespDTO.setKey(e.getKey());
                    processDefinitionRespDTO.setResourceName(e.getResourceName());
                    processDefinitionRespDTO.setDeploymentId(e.getDeploymentId());
                    processDefinitionRespDTO.setVersion(e.getVersion());

                    return processDefinitionRespDTO;
                })
                .collect(Collectors.toList());

        com.github.pagehelper.Page<ProcessDefinitionRespDTO> page = new com.github.pagehelper.Page<>(queryModel.getPageNum(), queryModel.getPageSize());
        page.setTotal(processDefinitionQuery.count());
        page.addAll(processDefinitions);
        return page.toPageInfo();
    }

    @Override
    public PageInfo<ProcessInstancesRespDTO> getInstances(QueryModel<String> queryModel) {
        GetProcessInstancesPayload getProcessInstancesPayload = new GetProcessInstancesPayload();
        if (queryModel.getCheckParam().isPresent()) {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(queryModel.getParam())
                    .singleResult();
            if (null == processDefinition) {
                throw new BusinessException(RCodeEnum.ERROR);
            }
            getProcessInstancesPayload.setProcessDefinitionKeys(CollectionUtil.newHashSet(processDefinition.getId()));
        }
        Page<org.activiti.api.process.model.ProcessInstance> processInstancesPage = processRuntime
                .processInstances(Pageable.of(0, 50), getProcessInstancesPayload);

        List<ProcessInstancesRespDTO> processInstancesList = processInstancesPage.getContent().stream().map(pi -> {
            ProcessInstancesRespDTO processInstancesRespDTO = new ProcessInstancesRespDTO();

            processInstancesRespDTO.setId(pi.getId());
            processInstancesRespDTO.setName(pi.getName());
            processInstancesRespDTO.setStatus(pi.getStatus().name());
            processInstancesRespDTO.setProcessDefinitionId(pi.getProcessDefinitionId());
            processInstancesRespDTO.setProcessDefinitionKey(pi.getProcessDefinitionKey());
            processInstancesRespDTO.setStartDate(pi.getStartDate());
            processInstancesRespDTO.setProcessDefinitionVersion(pi.getProcessDefinitionVersion());

            // 因为processRuntime.processDefinition("流程部署ID") 查询的结果没有部署流程与部署ID，所以用repositoryService查询
            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionId(pi.getProcessDefinitionId())
                    .singleResult();
            processInstancesRespDTO.setResourceName(pd.getResourceName());
            processInstancesRespDTO.setDeploymentId(pd.getDeploymentId());

            return processInstancesRespDTO;
        }).collect(Collectors.toList());

        com.github.pagehelper.Page<ProcessInstancesRespDTO> page = new com.github.pagehelper.Page<>(queryModel.getPageNum(), queryModel.getPageSize());
        page.setTotal(processInstancesPage.getTotalItems());
        page.addAll(processInstancesList);
        return page.toPageInfo();
    }

    /**
     * 创建实例
     *
     * @param processCreateTaskReqDTO processCreateTaskReqDTO
     * @return ProcessCreateTaskRespDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public ProcessCreateTaskRespDTO createTask(ProcessCreateTaskReqDTO processCreateTaskReqDTO) {
        log.info("【创建实例】，参数：{}", JSON.toJSONString(processCreateTaskReqDTO));

        // 获取流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(processCreateTaskReqDTO.getProcessKey())
                .singleResult();

        if (null == processDefinition) {
            throw new BusinessException(RCodeEnum.ACTIVITY_PROCESS_DEFINITION_NOT_EXIST);
        }

        Map<String, Object> variables = flowConditionService.handlerControlData(processCreateTaskReqDTO.getData());
        // 用于 条件判断
        variables.put(flowConditionService.FLOW_CONDITION_UTIL, flowConditionService);
        // 订单id
        variables.put(ActivityUtil.getProcessOrderIdKey(), processCreateTaskReqDTO.getOrderId());
        // 流程参数整合
        variables.put(ActivityUtil.VARIABLES, JSON.toJSONString(variables));

        // 创建实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variables);
        log.info("【创建实例】，流程实例id:{}", processInstance.getId());

        ProcessCreateTaskRespDTO processCreateTaskRespDTO = new ProcessCreateTaskRespDTO();
        processCreateTaskRespDTO.setProcessInstanceId(processInstance.getId());
        return processCreateTaskRespDTO;
    }

    /**
     * 流转实例
     *
     * @param processCompleteTaskReqDTO processCompleteTaskReqDTO
     * @return ProcessCompleteTaskRespDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public ProcessCompleteTaskRespDTO completeTask(ProcessCompleteTaskReqDTO processCompleteTaskReqDTO) {
        log.info("【流转实例】，参数：{}", JSON.toJSONString(processCompleteTaskReqDTO));

        String processInstanceId = processCompleteTaskReqDTO.getProcessInstanceId();
        NodeBaseDTO nodeBaseDTO = processCompleteTaskReqDTO.getNodeBaseDTO();

        CompleteTypeEnum completeTypeEnum = CompleteTypeEnum.isExistById(processCompleteTaskReqDTO.getCompleteType());

        // 查询当前任务
        ProcessTaskReqDTO processTaskReqDTO = new ProcessTaskReqDTO(processInstanceId, nodeBaseDTO);
        Task currentTask = this.isExistByProcessInstanceId(processTaskReqDTO);

        // 重新设置处理人
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        if (!currentTask.getAssignee().equals(username)) {
            taskService.setAssignee(currentTask.getId(), username);
        }
        switch (completeTypeEnum) {
            case PASS:
                // 通过
                this.pass(currentTask, processCompleteTaskReqDTO);
                break;
            case REFUSE:
                // 拒绝
                this.refuse(currentTask, processCompleteTaskReqDTO);
                break;
            case FALLBACK:
                // 回退
                this.fallback(currentTask, processCompleteTaskReqDTO);
                break;
            default:
                throw CompleteTypeEnum.getBusinessException();
        }
        ProcessCompleteTaskRespDTO processCompleteTaskRespDTO = new ProcessCompleteTaskRespDTO();
        processCompleteTaskRespDTO.setProcessInstanceId(processInstanceId);
        return processCompleteTaskRespDTO;
    }

    /**
     * 流转撤回
     *
     * @param taskId taskId
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void revokeTask(String taskId) {
        log.info("【流转撤回】，参数：{}", taskId);
        String username = SecurityContextHolder.getContext().getAuthentication().getName();

        Task task = taskService.createTaskQuery().processInstanceId(taskId).singleResult();
        if (task == null) {
            throw new BusinessException(RCodeEnum.ERROR, "流程未启动或已执行完成，无法撤回");
        }

        // 获取流程模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

        // 获取我最后处理节点id (flowId)
        String myLastActivityId = this.getMyLastActivityId(taskId);
        log.info("【流程撤销】，我最后处理节点：{}" + myLastActivityId);
        // 获取我最后处理节点 (node)
        FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myLastActivityId);

        // 获取活动节点id（flowId）
        String activitiId = bpmnModel.getFlowElement(task.getTaskDefinitionKey()).getId();
        log.info("【流程撤销】，当前活动节点：{}" + activitiId);
        // 获取我最后处理节点 (node)
        FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activitiId);

        // 记录原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<>(flowNode.getOutgoingFlows());

        // 清理活动方向
        flowNode.getOutgoingFlows().clear();

        // 建立新方向
        List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(flowNode);
        newSequenceFlow.setTargetFlowElement(myFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        flowNode.setOutgoingFlows(newSequenceFlowList);

        taskService.addComment(task.getId(), task.getProcessInstanceId(), "撤回");

        Map<String, Object> currentVariables = new HashMap<>();
        currentVariables.put("applier", username);

        // 完成任务
        taskService.complete(task.getId(), currentVariables);

        // 恢复原方向
        flowNode.setOutgoingFlows(oriSequenceFlows);
    }

    /**
     * 重新指派
     *
     * @param processReassignmentTaskReqDTO processChangeTaskReqDTO
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void reassignment(ProcessReassignmentTaskReqDTO processReassignmentTaskReqDTO) {
        log.info("【重新指派】，参数：{}", JSON.toJSONString(processReassignmentTaskReqDTO));
        String processInstanceId = processReassignmentTaskReqDTO.getProcessInstanceId();
        NodeBaseDTO nodeBaseDTO = processReassignmentTaskReqDTO.getNodeBaseDTO();
        UserEnterpriseDTO userEnterpriseDTO = processReassignmentTaskReqDTO.getUserEnterpriseDTO();

        String activitiUserId = ActivityUtil.toActivitiLoginUser(userEnterpriseDTO);

        ProcessTaskReqDTO processTaskReqDTO = new ProcessTaskReqDTO(processInstanceId, nodeBaseDTO);
        Task task = this.isExistByProcessInstanceId(processTaskReqDTO);

        taskService.unclaim(task.getId());

        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        String message = String.format("更换执行人操作。行人由%s更换为至%s", username, activitiUserId);
        taskService.addComment(task.getId(), task.getProcessInstanceId(), message);

        taskService.claim(task.getId(), activitiUserId);
    }

    /**
     * 实例列表
     *
     * @param queryModel queryModel
     * @return ProcessCompleteTaskRespDTO
     */
    @Override
    public PageInfo<ProcessTaskRespDTO> findTaskByAssignee(@Validated @RequestBody QueryModel<ProcessTaskReqDTO> queryModel) {
        int end = queryModel.getPageNum() * queryModel.getPageSize();
        Pageable of = Pageable.of(end - queryModel.getPageSize(), end);
        Page<org.activiti.api.task.model.Task> taskPage = taskRuntime.tasks(of);

        com.github.pagehelper.Page<ProcessTaskRespDTO> page = new com.github.pagehelper.Page<>(queryModel.getPageNum(), queryModel.getPageSize());
        page.setTotal(taskPage.getTotalItems());
        page.addAll(taskPage.getContent().stream()
                .map(task -> BeanUtil.copyProperties(task, ProcessTaskRespDTO.class))
                .collect(Collectors.toList()));

        return page.toPageInfo();
    }

    /**
     * 获取流程实例当前所在节点
     *
     * @param processInstanceId processInstanceId
     */
    @Override
    public List<Long> getCurrentNodeByTaskId(String processInstanceId) {
        return this.getActivityIdByProcessInstanceId(processInstanceId).stream().map(ActivityUtil::restoreFlowNodeId).collect(Collectors.toList());
    }

    /**
     * 获取流程可回退节点
     *
     * @param processTaskReqDTO processTaskReqDTO
     * @return List
     */
    @Override
    public List<Long> getCanFallbacks(ProcessTaskReqDTO processTaskReqDTO) {
        Task task = this.isExistByProcessInstanceId(processTaskReqDTO);
        // 获取当前模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        // 获取当前节点
        FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        return BpmnModelUtil.getCanFallbacks(flowElement).stream()
                .map(e -> ActivityUtil.restoreFlowNodeId(e.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 下载流程bpmn
     *
     * @param response response
     * @param id       id
     */
    @Override
    public void downBpmn(HttpServletResponse response, @NotBlank(message = "不能为空") String id) {
        try {
            InputStream inputStream = repositoryService.getResourceAsStream(id, ActivityUtil.getResourceName(1L));
            int count = inputStream.available();
            byte[] bytes = new byte[count];
            response.setContentType("text/xml");
            OutputStream outputStream = response.getOutputStream();
            while (inputStream.read(bytes) != -1) {
                outputStream.write(bytes);
            }
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取流程实例
     *
     * @param processTaskReqDTO processTaskReqDTO
     * @return Task
     */
    @Override
    public Task isExistByProcessInstanceId(ProcessTaskReqDTO processTaskReqDTO) {
        String username;
        if (null == processTaskReqDTO.getAssignee()) {
            username = ActivityUtil.getActivitiLoginUser();
        } else {
            username = ActivityUtil.toActivitiLoginUser(processTaskReqDTO.getAssignee());
        }
        // 查询当前任务
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processTaskReqDTO.getProcessInstanceId())
                .taskDefinitionKey(ActivityUtil.generateFlowNodeId(processTaskReqDTO.getNode()))
                .list();

        for (Task task : tasks) {
            List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(task.getId());
            if (identityLinks.stream().anyMatch(e -> e.getUserId().equals(username))) {
                return task;
            }
        }
        throw new BusinessException(RCodeEnum.ACTIVITY_TASK_NOT_EXIST);
    }

    /**
     * 获取我最后处理节点id
     *
     * @param taskId taskId
     * @return String
     */
    private String getMyLastActivityId(String taskId) {
        // 测试
        String userId = "";
        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(taskId)
                .orderByTaskCreateTime()
                .asc()
                .list();

        // 历史 获取我最后处理的任务实例
        HistoricTaskInstance myTask = null;
        for (HistoricTaskInstance hti : htiList) {
            if (userId.equals(hti.getAssignee())) {
                myTask = hti;
            }
        }

        if (null == myTask) {
            throw new BusinessException(RCodeEnum.ERROR, "该任务非当前用户提交，无法撤回");
        }

        // 历史 所有任务实例
        List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
                .executionId(myTask.getExecutionId())
                .finished()
                .list();

        // 历史 获取我最后活动的任务实例节点id
        String myActivityId = null;
        for (HistoricActivityInstance hai : haiList) {
            if (myTask.getId().equals(hai.getTaskId())) {
                myActivityId = hai.getActivityId();
            }
        }

        if (null == myActivityId) {
            throw new BusinessException(RCodeEnum.ERROR, "该任务非当前用户提交，无法撤回");
        }
        return myActivityId;
    }

    /**
     * 获取活动节点id
     *
     * @param processInstanceId processInstanceId
     * @return String
     */
    private List<String> getActivityIdByProcessInstanceId(String processInstanceId) {
        // 获取当前任务
        return taskService.createTaskQuery().processInstanceId(processInstanceId).list().stream()
                .map(task -> {
                    // 获取当前模型
                    BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
                    // 获取当前节点
                    FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
                    return flowElement.getId();
                }).collect(Collectors.toList());
    }

    /**
     * 通过
     *
     * @param currentTask               currentTask
     * @param processCompleteTaskReqDTO processCompleteTaskReqDTO
     */
    private void pass(Task currentTask, ProcessCompleteTaskReqDTO processCompleteTaskReqDTO) {
        Map<String, Object> variables = flowConditionService.handlerControlData(processCompleteTaskReqDTO.getData());
        variables.put(ActivityUtil.REMARK, processCompleteTaskReqDTO.getRemark());
        // 用于 条件判断
        variables.put(flowConditionService.FLOW_CONDITION_UTIL, flowConditionService);
        String processCompleteKey = ActivityUtil.getProcessCompleteKey(null);
        variables.put(processCompleteKey, ActivityUtil.getProcessNodeCompleteCondition());
        // 流程参数整合 用于流转和参数判断
        variables.put(ActivityUtil.VARIABLES, JSON.toJSONString(variables));
        // 记录流转类型
        variables.put(ActivityUtil.COMPLETE_TYPE, processCompleteTaskReqDTO.getCompleteType());
        taskService.complete(currentTask.getId(), variables, true);
    }

    /**
     * 回退
     *
     * @param currentTask               currentTask
     * @param processCompleteTaskReqDTO processCompleteTaskReqDTO
     */
    private void fallback(Task currentTask, ProcessCompleteTaskReqDTO processCompleteTaskReqDTO) {
        Long orderId = processCompleteTaskReqDTO.getOrderId();
        String processInstanceId = processCompleteTaskReqDTO.getProcessInstanceId();

        Map<String, Object> variables = flowConditionService.handlerControlData(processCompleteTaskReqDTO.getData());
        variables.put(ActivityUtil.REMARK, processCompleteTaskReqDTO.getRemark());
        // 用于 条件判断
        variables.put(flowConditionService.FLOW_CONDITION_UTIL, flowConditionService);
        // 流程参数整合 用于流转和参数判断
        variables.put(ActivityUtil.VARIABLES, JSON.toJSONString(variables));
        // 记录流转类型
        variables.put(ActivityUtil.COMPLETE_TYPE, processCompleteTaskReqDTO.getCompleteType());

        // 获取当前模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(currentTask.getProcessDefinitionId());
        // 获取回退目标节点
        String fallbackFlowId = ActivityUtil.generateFlowNodeId(processCompleteTaskReqDTO.getFallbackNode());
        UserTask fallback = (UserTask) bpmnModel.getFlowElement(fallbackFlowId);
        // 获取当前节点
        UserTask currentFlowElement = (UserTask) bpmnModel.getFlowElement(currentTask.getTaskDefinitionKey());

        // 然后处理当前节点
        BpmnModelUtil.tempSequenceFlow(currentFlowElement, fallback, SequenceFlowTypeEnum.FALLBACK, null, () -> {
            // 获取当前实例所有Execution
            List<Execution> executions = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();

            // 过滤活跃 && 节点 && 非当前节点Execution
            Map<String, List<ExecutionEntityImpl>> executionEntitiesMap = executions.stream()
                    .filter(e -> e instanceof ExecutionEntityImpl && Objects.nonNull(e.getActivityId()) && !e.getId().equals(currentTask.getExecutionId()))
                    .map(e -> (ExecutionEntityImpl) e)
                    .collect(Collectors.groupingBy(ExecutionEntityImpl::getActivityId));

            // 获取回退目标节点所有后代
            List<String> familyIds = BpmnModelUtil.getFamilyFlows(fallback, false).stream()
                    .map(BaseElement::getId)
                    .collect(Collectors.toList());

            // 获取Execution管理器
            DbSqlSession dbSqlSession = managementService.executeCommand(new GetDbSqlSessionCmd());

            // 先处理网关
            executionEntitiesMap.forEach((flowId, executionEntities) -> {
                if (familyIds.contains(flowId)) {
                    if (ActivityUtil.restoreFlowNodeTypeEnum(flowId).isGateway()) {
                        executionEntities.forEach(dbSqlSession::delete);
                    }
                }
            });

            // 然后处理用户节点
            Set<Long> suspendNodeIds = new HashSet<>();
            executionEntitiesMap.forEach((flowId, executionEntities) -> {
                if (familyIds.contains(flowId)) {
                    if (ActivityUtil.restoreFlowNodeTypeEnum(flowId).isUserTask()) {
                        UserTask userTask = (UserTask) bpmnModel.getFlowElement(flowId);
                        EndEvent stopEvent = (EndEvent) bpmnModel.getFlowElement(ActivityUtil.generateStopNodeId());

                        BpmnModelUtil.tempSequenceFlow(userTask, stopEvent, SequenceFlowTypeEnum.COMPLETE, null, () -> {
                            executionEntities.forEach(e -> {
                                Task task = taskService.createTaskQuery()
                                        .processInstanceId(processInstanceId)
                                        .executionId(e.getId())
                                        .singleResult();
                                if (null != task) {
                                    taskService.complete(task.getId(), variables, true);
                                    log.info("【节点回退监听器】，已终止taskId：{}，从属节点：{}", task.getId(), flowId);
                                    suspendNodeIds.add(ActivityUtil.restoreFlowNodeId(flowId));
                                }
                            });
                        });
                    }
                }
            });

            // 回退当前节点
            taskService.complete(currentTask.getId(), variables, true);

            // 挂起订单数据 当前活跃所有节点
            if (!suspendNodeIds.isEmpty()) {
                ChangeOrderNodeDataReqDTO changeOrderNodeDataReqDTO = new ChangeOrderNodeDataReqDTO();
                changeOrderNodeDataReqDTO.setOrderId(orderId);
                changeOrderNodeDataReqDTO.setNodeIds(new ArrayList<>(suspendNodeIds));
                changeOrderNodeDataReqDTO.setHandleType(HandleTypeEnum.SUSPEND.getId());
                remoteApplicationOrderNodeService.changeOrderNodeData(changeOrderNodeDataReqDTO);
            }
        });
    }

    /**
     * 拒绝
     *
     * @param currentTask               currentTask
     * @param processCompleteTaskReqDTO processCompleteTaskReqDTO
     */
    private void refuse(Task currentTask, ProcessCompleteTaskReqDTO processCompleteTaskReqDTO) {
        Map<String, Object> variables = flowConditionService.handlerControlData(processCompleteTaskReqDTO.getData());
        variables.put(ActivityUtil.REMARK, processCompleteTaskReqDTO.getRemark());
        // 用于 条件判断
        variables.put(flowConditionService.FLOW_CONDITION_UTIL, flowConditionService);
        // 流程参数整合 用于流转和参数判断
        variables.put(ActivityUtil.VARIABLES, JSON.toJSONString(variables));
        // 记录流转类型
        variables.put(ActivityUtil.COMPLETE_TYPE, processCompleteTaskReqDTO.getCompleteType());

        // 获取当前模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(currentTask.getProcessDefinitionId());
        EndEvent refuse = (EndEvent) bpmnModel.getFlowElement(ActivityUtil.generateRefuseNodeId());
        UserTask userTask = (UserTask) bpmnModel.getFlowElement(currentTask.getTaskDefinitionKey());

        // 流程拒绝监听器
        ActivitiListener refuseListener = BpmnModelUtil.createExecutionListener(EventTypeEnum.TAKE, TaskRefuseListener.class);

        // 然后处理当前节点
        BpmnModelUtil.tempSequenceFlow(userTask, refuse, SequenceFlowTypeEnum.REFUSE, refuseListener, () ->
                taskService.complete(currentTask.getId(), variables, true));
    }
}
